/**
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.gitee.huangjianbo.supos.openapi.httpclient5.interceptors;

import org.apache.hc.core5.http.*;
import org.apache.hc.core5.http.message.BasicHeader;
import org.apache.hc.core5.http.protocol.HttpContext;
import org.apache.hc.core5.net.URIBuilder;

import io.gitee.huangjianbo.supos.openapi.core.aksk.AKSKGenerator;
import io.gitee.huangjianbo.supos.openapi.core.config.SuposApiClientConfig;
import io.gitee.huangjianbo.supos.openapi.core.enums.AuthorizationType;
import io.gitee.huangjianbo.supos.openapi.core.errors.ApiClientException;
import io.gitee.huangjianbo.supos.openapi.core.http.HttpHeaders;
import io.gitee.huangjianbo.supos.openapi.core.thread.ClientContext;
import io.gitee.huangjianbo.supos.openapi.core.thread.ClientContextHolder;
import io.gitee.huangjianbo.supos.openapi.core.tools.StringUtils;

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 认证头设置拦截器
 *
 * @author tomcat
 * @version 1.0
 */
public class AuthorizationHeaderInterceptor implements HttpRequestInterceptor {

    private final SuposApiClientConfig globalConfig;

    public AuthorizationHeaderInterceptor(SuposApiClientConfig globalConfig) {
        this.globalConfig = globalConfig;
    }

    @Override
    public void process(HttpRequest request, EntityDetails entity, HttpContext context) throws HttpException, IOException {
        ClientContext clientContext = ClientContextHolder.getContext();

        String ticket = globalConfig.getTicket();
        if (clientContext != null && StringUtils.isNotEmpty(clientContext.getTicket())) {
            ticket = clientContext.getTicket();
        }

        if (StringUtils.isNotEmpty(ticket)) {
            String auth = AuthorizationType.Bearer.name() + " " + ticket;
            request.addHeader(new BasicHeader(HttpHeaders.AUTHORIZATION, auth));
        } else {
            String ak = globalConfig.getAccessKey();
            if (clientContext != null && StringUtils.isNotEmpty(clientContext.getAccessKey())) {
                ak = clientContext.getAccessKey();
            }
            String sk = globalConfig.getSecretKey();
            if (clientContext != null && StringUtils.isNotEmpty(clientContext.getSecretKey())) {
                sk = clientContext.getSecretKey();
            }
            if (StringUtils.isEmpty(ak) || StringUtils.isEmpty(sk)) {
                throw new ApiClientException("The access key or secret key must be not empty");
            }
            URIBuilder uriBuilder;
            try {
                uriBuilder = new URIBuilder(request.getUri());
            } catch (URISyntaxException e) {
                throw new ApiClientException("Fail to create signature authorization header", e);
            }
            String method = request.getMethod().toUpperCase();
            String path = uriBuilder.getPath();
            String contentType = request.getLastHeader(HttpHeaders.CONTENT_TYPE).getValue();
            String queryParams = getQueryParamsString(uriBuilder.getQueryParams());
            Map<String, String> headers = getHeaders(request.getHeaders());

            String sign = AKSKGenerator.sign(method, path, contentType, headers, queryParams, ak, sk);
            request.addHeader(new BasicHeader(HttpHeaders.AUTHORIZATION, AuthorizationType.Sign.name() + " " + sign));
        }
    }

    /**
     * 获取请求头
     *
     * @param headers 请求头列表
     * @return Map
     */
    private Map<String, String> getHeaders(Header[] headers) {
        final Map<String, String> result = new HashMap<>();
        if (headers != null && headers.length > 0) {
            Arrays.stream(headers).forEach(header -> result.put(header.getName(), header.getValue()));
        }
        return result;
    }

    /**
     * 获取请求参字符串
     *
     * @param pairs 请求参列表
     * @return 字符串格式
     */
    private String getQueryParamsString(List<NameValuePair> pairs) {
        if (pairs != null && !pairs.isEmpty()) {
            return StringUtils.join(pairs.stream()
                    .map(p -> p.getName() + "=" + p.getValue())
                    .collect(Collectors.toList()), "&");
        }
        return "";
    }
}
